package vue;


import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.filechooser.FileNameExtensionFilter;

import controleur.QRCommon;

import reedSolomon.ReedSolomon;

import matrice.MaskPattern;
import matrice.QRCode;

import dataMode.ModeDetection;
import dataMode.QR8Bit;
import dataMode.QRAlphaNumeric;
import dataMode.QRData;
import dataMode.QRKanji;
import dataMode.QRNum;

public class QRCodeFrame extends JFrame implements ActionListener {

	private static final long serialVersionUID = 1L;
	
	private JButton btnEncode;
	private JButton btnExport;
	private JPanel panelInput;
	private JPanel panelOutput;
	private JLabel lblEncode;
	private JLabel lblEccLevel;
	private JLabel lblSize;
	private JTextField txtEncode;
	private JComboBox comboEccLevel;
	private JComboBox comboSize;
	private JLabel lblImage;

	
	public QRCodeFrame() {
		
		buildInterface();
		buildEvents();
	}
	
	private void buildInterface() {
		setLayout(new BorderLayout());
		setTitle("QR Code Generator");
		setResizable(false);
		setLocationRelativeTo(getParent()); // Centre la fenetre
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		panelInput = new JPanel(new GridLayout(4, 2));
		panelOutput = new JPanel(new BorderLayout());
		
		// Label
		lblEncode = new JLabel("Texte à encoder :");
		
		// Champ texte a encoder
		txtEncode = new JTextField(30);
		
		lblEccLevel = new JLabel("Niveau de redondance : ");
		comboEccLevel = new JComboBox();
		comboEccLevel.addItem("L");
		comboEccLevel.addItem("M");
		comboEccLevel.addItem("Q");
		comboEccLevel.addItem("H");
		
		lblSize = new JLabel("Taille du QRCode :");
		comboSize = new JComboBox();
		comboSize.addItem("Petit");
		comboSize.addItem("Moyen");
		comboSize.addItem("Grand");
		comboSize.addItem("Très grand");
		
		btnEncode = new JButton("Générer le QRCode");		
		btnExport = new JButton("Exporter le QRcode");
		
		lblImage = new JLabel("",JLabel.CENTER);
		
		btnExport.setVisible(false);
		
		panelInput.add(lblEncode);
		panelInput.add(txtEncode);
		panelInput.add(lblEccLevel);
		panelInput.add(comboEccLevel);
		panelInput.add(lblSize);
		panelInput.add(comboSize);
		panelOutput.add(btnEncode, BorderLayout.NORTH);
		panelOutput.add(btnExport, BorderLayout.SOUTH);

		panelOutput.add(lblImage, BorderLayout.CENTER);
		getContentPane().add(panelInput, BorderLayout.NORTH);
		getContentPane().add(panelOutput, BorderLayout.CENTER);

		pack();
	}

	private void buildEvents() {
		btnEncode.addActionListener(this);
		btnExport.addActionListener(this);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		//Appel les fonctions d'encodage et affiche le qrcode
		if(e.getSource() == btnEncode || e.getSource() == btnExport) {
			String textValue = txtEncode.getText();
			int version=0, eccLvl=0;
			String strSize = (String) comboSize.getSelectedItem();
			String strEccLevel = (String) comboEccLevel.getSelectedItem();
			
			if(strSize.equals("Petit"))
				version = 1;
			else if(strSize.equals("Moyen"))
				version = 5;
			else if(strSize.equals("Grand"))
				version = 25;
			else if(strSize.equals("Très grand"))
				version = 40;
			
			if(strEccLevel.equals("L"))
				eccLvl = QRData.ERROR_CORR_LVL_L;
			else if(strEccLevel.equals("M"))
				eccLvl = QRData.ERROR_CORR_LVL_M;
			else if(strEccLevel.equals("H"))
				eccLvl = QRData.ERROR_CORR_LVL_H;
			else if(strEccLevel.equals("Q"))
				eccLvl = QRData.ERROR_CORR_LVL_Q;
			
			/* Contruction des données */
			QRImage img = new QRImage(10, 20);
			Boolean[][] matrice = getMatrice(textValue, version, eccLvl);
			
			if(matrice == null) {
				JOptionPane.showConfirmDialog(this, "La longueur de la chaîne saisie est trop grande " +
						"pour la version et le niveau de redondance sélectionné", "Erreur", JOptionPane.CLOSED_OPTION, JOptionPane.ERROR_MESSAGE);
			}
			else {
				BufferedImage imgbuff = img.getImage(matrice);
			
				// Affiche le QRCode dans la JFrame
				if(e.getSource() == btnEncode) {
					lblImage.setIcon(new ImageIcon(imgbuff));
					panelOutput.remove(lblImage);
					panelOutput.add(lblImage, BorderLayout.CENTER);
					btnExport.setVisible(true);
					pack();
				}			
				// Exporte le QRCode en tant que fichier
				else if(e.getSource() == btnExport) {
									
					JFileChooser dialogChooser = new JFileChooser();
					dialogChooser.setSelectedFile(new File("qrcode.png"));
					
					FileNameExtensionFilter filter = new FileNameExtensionFilter("Image", new String[]{"png"});
					dialogChooser.setFileFilter(filter);
					
					if (dialogChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
		
						File file = dialogChooser.getSelectedFile();
						String path = file.getAbsolutePath();
						String fullPath = "";
						
						if(path.endsWith(".png"))
							fullPath = path;
						else
							fullPath = path+".png";
						
						File fi= new File(fullPath);
						
					 	try {
					 		ImageIO.write(imgbuff, "png", fi);
					 	} catch (IOException ioe) {
					 		ioe.printStackTrace();
					 	}
					}
				}
			}
		}
	}
	
	private Boolean[][] getMatrice(String text, int version, int eccLvl) {

		QRData data = null;
		
		// Instancie data en fonction du type de donnée saisi
		switch(ModeDetection.testMode(text)) {
			case QRData.MODE_ALPHANUMERIC: data = new QRAlphaNumeric(text, version, eccLvl);
				break;
			case QRData.MODE_BINARY: data = new QR8Bit(text, version, eccLvl);
				break;
			case QRData.MODE_KANJI: data = new QRKanji(text, version, eccLvl);
				break;
			case QRData.MODE_NUMERIC: data = new QRNum(text, version, eccLvl);
				break;
		}
		
		// Test de la taille de la chaine saisie
		if(text.length() > QRCommon.getInputMaxLength(version, data.getMode(), eccLvl)) {
			return null;
		}
		else {
			System.out.println("MODE : "+data.getMode());
			System.out.println("VERSION : "+data.getVersion());
			System.out.println("ECC LEVEL : "+data.getErrorCorrectionLevel());
			System.out.println("LONGUEUR DATA : "+data.getBinaryData().length());
			
			/* Incorporation du code correction RS dans data */
			ReedSolomon rs = new ReedSolomon(data);
			data.addRsCodeBlocks(rs.getStringParity());
			
			System.out.println("NOMBRE DE PAQUETS 8bits REED SOLOMON   : "+rs.getNbErrorCorrectionCode());
			System.out.println("NOMBRE DE BLOC DE CODE DE REED SOLOMON :  "+rs.getNbRSBlocks());
			// Construction de la structure de base du Qrcode (Detection pattern etc...)
			QRCode qrcode = new QRCode(data);
		
			MaskPattern mp = new MaskPattern(qrcode.getMatrice(), data);
		
			System.out.println("\nMATRICE FINALE\n");
			System.out.println("NUMERO DE MASQUE  : "+mp.getNumMask());
			System.out.println("SCORE DE PENALITE : "+mp.getScore());
			
			return mp.getMatrice();
		}
	}
}
